/**
 * @file 应用级通知独立窗口（全局）
 * @description 在主进程维护一个置顶、无框的小窗口，用于显示全局通知弹窗，不受各渲染窗口遮挡
 */

import type { BrowserWindowConstructorOptions, Rectangle, WebContents } from 'electron'
import { BrowserWindow, ipcMain, screen } from 'electron'
import { getPreloadPath, getWindowUrl } from '#/utils/paths'
import { NOTIFICATION_WINDOW_CHANNELS } from '~shared/ipc-topic'

let win: BrowserWindow | null = null
let ipcRegistered = false

// 当前锚定的父窗口（用于相对定位到应用窗口内部）
let anchorWin: BrowserWindow | null = null
let detachAnchorListeners: (() => void) | null = null
// 最近一次请求的定位参数（用于在窗口内容尺寸变化时仍保持锚定位置一致）
let lastPosition: Notify.NotificationPosition = 'top-right'
let lastCustomX: number | undefined
let lastCustomY: number | undefined

function calcBoundsInParentByPosition(
  parent: BrowserWindow,
  width: number,
  height: number,
  position: Notify.NotificationPosition,
  margin = 12,
  customX?: number,
  customY?: number
): Rectangle {
  const cb = parent.getContentBounds()
  const clampX = (x: number) => cb.x + Math.max(0, Math.min(x, Math.max(0, cb.width - width)))
  const clampY = (y: number) => cb.y + Math.max(0, Math.min(y, Math.max(0, cb.height - height)))
  switch (position) {
    case 'top-left': {
      return { x: cb.x + margin, y: cb.y + margin, width, height }
    }
    case 'top-center': {
      return {
        x: cb.x + Math.max(0, Math.floor((cb.width - width) / 2)),
        y: cb.y + margin,
        width,
        height
      }
    }
    case 'top-right': {
      return { x: cb.x + Math.max(0, cb.width - width - margin), y: cb.y + margin, width, height }
    }
    case 'bottom-left': {
      return { x: cb.x + margin, y: cb.y + Math.max(0, cb.height - height - margin), width, height }
    }
    case 'bottom-center': {
      return {
        x: cb.x + Math.max(0, Math.floor((cb.width - width) / 2)),
        y: cb.y + Math.max(0, cb.height - height - margin),
        width,
        height
      }
    }
    case 'bottom-right': {
      return {
        x: cb.x + Math.max(0, cb.width - width - margin),
        y: cb.y + Math.max(0, cb.height - height - margin),
        width,
        height
      }
    }
    case 'custom': {
      const x = typeof customX === 'number' ? customX : margin
      const y = typeof customY === 'number' ? customY : margin
      return { x: clampX(x), y: clampY(y), width, height }
    }
    default: {
      // 兜底：右上角
      return { x: cb.x + Math.max(0, cb.width - width - margin), y: cb.y + margin, width, height }
    }
  }
}

function positionWindowByAnchor(width: number, height: number) {
  if (!win || win.isDestroyed()) return
  const pos: Rectangle =
    anchorWin && !anchorWin.isDestroyed()
      ? calcBoundsInParentByPosition(
          anchorWin,
          width,
          height,
          lastPosition,
          12,
          lastCustomX,
          lastCustomY
        )
      : calcTopRightBounds(width, height)
  win.setBounds(pos, false)
}

function setAnchorWindow(newAnchor: BrowserWindow | null) {
  if (anchorWin === newAnchor) return
  // 解绑旧监听
  if (detachAnchorListeners && anchorWin && !anchorWin.isDestroyed()) {
    try {
      detachAnchorListeners()
    } catch {
      /* empty */
    }
  }
  anchorWin = newAnchor
  detachAnchorListeners = null

  // 绑定父子关系：仅在应用内部置顶，不跨应用置顶
  if (win && !win.isDestroyed()) {
    try {
      win.setParentWindow(anchorWin ?? null)
    } catch {
      /* empty */
    }
  }

  if (anchorWin && !anchorWin.isDestroyed()) {
    const onMove = () => {
      const b = win?.getBounds()
      positionWindowByAnchor(b?.width ?? 380, b?.height ?? 80)
    }
    const onResize = () => {
      const b = win?.getBounds()
      positionWindowByAnchor(b?.width ?? 380, b?.height ?? 80)
    }
    anchorWin.on('move', onMove)
    anchorWin.on('resize', onResize)
    detachAnchorListeners = () => {
      anchorWin?.off('move', onMove)
      anchorWin?.off('resize', onResize)
    }
  }
}

function ensureIpc() {
  if (ipcRegistered) return
  ipcRegistered = true

  ipcMain.handle(
    NOTIFICATION_WINDOW_CHANNELS.SET_SIZE,
    (_evt, payload: { width?: number; height?: number }) => {
      // console.log('[Notifications] 设置通知窗口大小:', payload)
      try {
        const { width, height } = payload || {}
        if (!win || win.isDestroyed()) return { success: false }
        const bounds = win.getBounds()
        const w = Math.max(260, Math.min(width ?? bounds.width, 600))
        const h = Math.max(50, Math.min(height ?? bounds.height, 800))
        positionWindowByAnchor(w, h)
        return { success: true }
      } catch (error) {
        return { success: false, error: (error as Error).message }
      }
    }
  )
}

function createWindow(): BrowserWindow {
  const opts: BrowserWindowConstructorOptions = {
    width: 380,
    height: 80,
    frame: false,
    // modal: true,
    transparent: true,
    resizable: false,
    movable: false,
    minimizable: false,
    maximizable: false,
    show: false,
    alwaysOnTop: false,
    focusable: true,
    webPreferences: {
      preload: getPreloadPath('internal'),
      backgroundThrottling: false,
      devTools: process.env.NODE_ENV !== 'production',
      sandbox: false
    }
  }

  const w = new BrowserWindow(opts)
  positionWindowByAnchor(opts.width!, opts.height!)

  w.loadURL(getWindowUrl('notifications')).catch(error => {
    console.error('[Notifications] 加载通知窗口失败:', error)
  })

  w.on('closed', () => {
    try {
      detachAnchorListeners && detachAnchorListeners()
    } catch {
      /* empty */
    }
    win = null
  })
  w.webContents.on('dom-ready', () => {
    w.webContents.openDevTools()
  })

  return w
}

function calcTopRightBounds(width: number, height: number, margin = 12): Rectangle {
  const display = screen.getPrimaryDisplay()
  const { workArea } = display
  const x = workArea.x + workArea.width - width - margin
  const y = workArea.y + margin
  return { x, y, width, height }
}

export function getNotificationWindow(): BrowserWindow {
  if (win && !win.isDestroyed()) return win
  ensureIpc()
  win = createWindow()
  return win!
}

export function showNotificationWindow(payload: Notify.NotificationOptions, sender?: WebContents) {
  const w = getNotificationWindow()
  // 选择锚定的父窗口：优先使用消息来源的窗口，其次使用当前聚焦窗口，最后退回任一窗口
  let parent: BrowserWindow | null = null
  try {
    parent = (sender ? BrowserWindow.fromWebContents(sender) : null) ?? null
  } catch {
    /* empty */
  }
  if (!parent || parent.isDestroyed()) parent = BrowserWindow.getFocusedWindow() ?? null
  if (!parent || parent.isDestroyed()) parent = BrowserWindow.getAllWindows()[0] ?? null

  // 记录本次请求的位置参数
  lastPosition = (payload.position ?? 'top-right') as Notify.NotificationPosition
  if (lastPosition === 'custom') {
    lastCustomX = typeof payload.x === 'number' ? payload.x : 0
    lastCustomY = typeof payload.y === 'number' ? payload.y : 0
  } else {
    lastCustomX = undefined
    lastCustomY = undefined
  }

  setAnchorWindow(parent || null)
  console.log(
    '[Notifications] 显示通知窗口:',
    payload,
    '\n',
    sender?.id,
    '\n',
    parent.contentView,
    '\n',
    parent.webContents,
    '\n',
    BrowserWindow.getFocusedWindow(),
    '\n',
    BrowserWindow.getAllWindows()
  )
  // 根据锚点定位
  const b = w.getBounds()
  positionWindowByAnchor(b.width, b.height)

  if (w.isVisible()) {
    // forward message directly
    w.webContents.send('notification-window:push', payload)
  } else {
    w.webContents.once('did-finish-load', () => {
      w.webContents.send('notification-window:push', payload)
    })
    // show without stealing focus
    w.showInactive()
  }
}

export function clearNotificationWindow() {
  const w = getNotificationWindow()
  console.log('[Notifications] 清空通知窗口', w)
  if (w && !w.isDestroyed()) {
    w.webContents.send('notification-window:clear')
  }
  w?.close()
}
